package com.eastmoney.emis.edda.task.eddi.processor;

import com.eastmoney.emis.edda.config.HsbcEddaConfig;
import com.eastmoney.emis.edda.domain.entity.EddiInstruction;
import com.eastmoney.emis.edda.domain.event.EddiInstructionEvent;
import com.eastmoney.emis.edda.domain.event.EventPublisher;
import com.eastmoney.emis.edda.domain.repository.HsbcEddiRepository;
import com.eastmoney.emis.edda.domain.valueobject.EddiOperation;
import com.eastmoney.emis.edda.domain.valueobject.EddiStatus;
import com.eastmoney.emis.edda.domain.valueobject.PaymentStatus;
import com.eastmoney.emis.edda.infrastructure.hsbc.HsbcEddaApi;
import com.eastmoney.emis.edda.infrastructure.hsbc.dto.AccountDto;
import com.eastmoney.emis.edda.infrastructure.hsbc.dto.InstructionReq;
import com.eastmoney.emis.edda.infrastructure.hsbc.dto.InstructionResp;
import com.eastmoney.emis.edda.task.eddi.EddiTask;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * @description: Description
 * @projectName: EDDA-HSBC
 * @package: com.eastmoney.emis.edda.task.eddi
 * @author: 汪程程
 * @date: 2022/10/13 2:27 PM
 * @version: 1.0
 */
@Order(0)
@Component
public class EddiInitProcessor implements EddiProcessor {

    @Autowired
    private HsbcEddaConfig config;
    @Autowired
    private HsbcEddaApi eddaApi;
    @Autowired
    private HsbcEddiRepository eddiRepository;
    @Autowired
    private EventPublisher eventPublisher;

    @Override
    public boolean canProcess(String status) {
        return EddiStatus.INIT.value().equals(status);
    }

    @Override
    public void execute(EddiTask task) {
        EddiInstruction eddiInstruction = task.getEddiInstruction();
        eddiInstruction.setStatus(EddiStatus.BANK_PROCESS);
        InstructionReq req = new InstructionReq();
        req.MerchantInstructionIdentification = eddiInstruction.getApplySerialNo();
        req.MandateIdentification = eddiInstruction.getMandateId();
        req.CreditorAccount = new AccountDto(config.getCreditorAccount());
        req.InstructedAmount = eddiInstruction.getOccurBalance().toString();
        req.CreditorReference = task.getCreditorReference();
        req.SmsLanguageCode = task.getLanguage();
        InstructionResp resp = eddaApi.debitInstruction(req);
        resp.onSuccess(r -> {
            eddiInstruction.setStatus(PaymentStatus.parse(resp.PaymentInformationStatus).transferToEddiStatus());
            eddiInstruction.setTransactionId(resp.TransactionIdentification);
        }).onFail(r -> {
            EddiStatus status = duplicateRequest(resp.errorCodes()) ? EddiStatus.BANK_PROCESS : EddiStatus.BANK_PROCESS_FAIL;
            eddiInstruction.setStatus(status);
        });
        eddiRepository.saveDebitInstruction(eddiInstruction);
        publishEvent(task, resp);
    }

    private boolean duplicateRequest(String errorCodes) {
        // MFD10007:Duplicate Merchant Instruction Identification
        return errorCodes.contains("MFD10007");
    }

    private void publishEvent(EddiTask task, InstructionResp instructionResp) {
        EddiInstructionEvent event = new EddiInstructionEvent(task.getEddiInstruction());
        event.setProcessUid(task.getProcessUid());
        event.setProcessUserName(task.getProcessUserName());
        event.setResult(instructionResp.result());
        event.setApplyReq(instructionResp.context().getReqPayload());
        event.setApplyRes(instructionResp.context().getRespPayload());
        event.setOperation(EddiOperation.BANK_PROCESS.getValue());
        event.setErrorReason(instructionResp.rejectReason());
        eventPublisher.publish(event);
    }

}
